public class PhysicsObject {
	float mass;
	Vector2f position;
	Vector2f velocity;
	Vector2f acceleration;
	SceneGraphNode renderable;
	
	public PhysicsObject() {
		mass = 1;
		position = new Vector2f();
		velocity = new Vector2f();
		acceleration = new Vector2f();
	}

	public void updateState(float timePeriod) {
		position.sumScale(velocity, timePeriod);
		position.sumScale(acceleration, timePeriod * timePeriod / 2);
		velocity.sumScale(acceleration, timePeriod);
		
		if (renderable != null) {
			renderable.translateX = position.x;
			renderable.translateY = position.y;
		}
	}

	public CollisionInfo getCollision(PhysicsObject other) {
		if (mass == Float.POSITIVE_INFINITY && other.mass == Float.POSITIVE_INFINITY)
			return null;
		if (this instanceof HalfSpace && other instanceof Circle)
			return getCollision((HalfSpace)this, (Circle)other);
		if (this instanceof Circle && other instanceof HalfSpace) {
			CollisionInfo cInfo = getCollision((HalfSpace)other, (Circle)this);
			if (cInfo != null)
				cInfo.normal.scale(-1);
			return cInfo;
		}
		if (this instanceof Circle && other instanceof Circle)
			return getCollision((Circle)this, (Circle)other);
		return null;
	}
	
	private CollisionInfo getCollision(HalfSpace a, Circle b) {
		float distance = a.normal.dot(b.position);
		distance -= a.intercept;
		if (distance > b.radius)
			return null;
		CollisionInfo cInfo = new CollisionInfo();
		cInfo.depth = b.radius - distance;
		cInfo.normal = new Vector2f(a.normal);
		// cInfo.position = ???
		return cInfo;
	}
	
	private CollisionInfo getCollision(Circle a, Circle b) {
		Vector2f tmp = new Vector2f(b.position);
		tmp.sumScale(a.position, -1);
		float distance = tmp.length() - a.radius - b.radius;
		if (distance > 0)
			return null;
		CollisionInfo cInfo = new CollisionInfo();
		cInfo.depth = -distance;
		tmp.normalize();
		cInfo.normal = tmp;
		// cInfo.position = ???
		return cInfo;
	}
	
	public void resolveCollision(PhysicsObject other, CollisionInfo cInfo) {
		// Calculate the relative velocity between the calling object and
		// other object, as if the calling object were stationary and only
		// the other object were moving.
		Vector2f relativeVelocity = new Vector2f(other.velocity);
		relativeVelocity.sumScale(velocity, -1);
		// Calculate the component of the relative velocity that lays along
		// the collision normal.
		float compRelVelAlongNormal = relativeVelocity.dot(cInfo.normal);
		// If the objects are moving away from each other, do nothing and hope
		// the collision will resolve itself next frame.
		if (compRelVelAlongNormal >= 0)
			return;
		// Calculate the total desired change in velocity due to the collision
		// (technically an impulse).
		Vector2f totalChangeInVelocity = new Vector2f(cInfo.normal);
		totalChangeInVelocity.scale(2 * compRelVelAlongNormal);
		// Calculate the proportion of the total change in velocity that will
		// be applied to each object (mass proportionate).
		float proportionForA, proportionForB;
		// Temporary hack to handle infinite masses.
		if (mass == Float.POSITIVE_INFINITY) {
			proportionForA = 0;
			proportionForB = 1;
		} else if (other.mass == Float.POSITIVE_INFINITY) {
			proportionForA = 1;
			proportionForB = 0;
		} else {
			proportionForA = other.mass / (mass + other.mass);
			proportionForB = mass / (mass + other.mass);
		}
		// Apply the correct velocity change to each object.
		velocity.sumScale(totalChangeInVelocity, proportionForA);
		other.velocity.sumScale(totalChangeInVelocity, -proportionForB);
	}
}
